#include <iostream>
#include <memory>
#include "epoll_object.hpp"
#include "socket.hpp"
#include "Log.hpp"

const static int back_log = 32;

class EpollServer
{
    static const int max_events = 64;

private:
    void HandlerEvent(int event_num)
    {
        lg.LogMessage(Debug, "ready event num = %d\n", event_num);
        for (size_t i = 0; i < event_num; i++)
        {
            int sock_fd = _events[i].data.fd;
            uint32_t event = _events[i].events;
            // 可以用封装多一层打印event为字符串
            lg.LogMessage(Debug, "ready fd: %d, Event is: %u\n", sock_fd, event);

            if (event & EPOLLIN)
            {
                if (_listen_sock->GetSockFd() == sock_fd)
                {
                    std::string client_ip;
                    uint16_t client_port;

                    // 可以封装成Accepter函数
                    int fd = _listen_sock->AcceptConnection(&client_ip, &client_port);
                    if (fd < 0)
                    {
                        lg.LogMessage(Error, "accept failed, error is %s, code is %d\n", strerror(errno), errno);
                    }
                    _epoller->AddEvent(fd, EPOLLIN);
                    lg.LogMessage(Info, "accept client success, client[%s:%d]\n", client_ip.c_str(), client_port);
                }
                else
                {
                    char buffer[1024];
                    ssize_t n = recv(sock_fd, buffer, sizeof(buffer) - 1, 0);
                    if (n > 0)
                    {
                        buffer[n] = 0;
                        std::cout << "client message# " << buffer << std::endl;

                        std::string message = "server message: ";
                        message+=buffer;
                        send(sock_fd, message.c_str(), message.size(), 0);
                    }
                    else
                    {
                        if (n == 0)
                        {
                            // 对端关闭
                            lg.LogMessage(Info, "client close fd...");
                        }
                        else
                        {
                            lg.LogMessage(Error, "read failed, error is %s, code is %d\n", strerror(errno), errno);
                        }
                        _epoller->DelEvent(sock_fd);
                        close(sock_fd);
                    }
                }
            }
        }
    }

public:
    EpollServer(int port) : _port(port), _isrunning(false), _listen_sock(new NetWork::TcpSocket) {}
    bool InitServer()
    {
        // 设置listen套接字
        _listen_sock->BuildListenSocketMethod(_port, back_log);
        lg.LogMessage(Info, "init listen_sock success, fd = %d\n", _listen_sock->GetSockFd());

        // 构建Epoll模型
        _epoller->InitEpoller();

        // 将listen套接字添加到为关心事件
        _epoller->AddEvent(_listen_sock->GetSockFd(), EPOLLIN);

        return true;
    }
    void Loop()
    {
        _isrunning = true;
        while (1)
        {
            int timeout = 2000;
            int num_event = _epoller->WaitEpoller(&_events, max_events, timeout);

            if (num_event > 0)
            {
                lg.LogMessage(Info, "events are ready...\n");
                HandlerEvent(num_event);
            }
            else if (num_event == 0)
            {
                lg.LogMessage(Info, "time out, events unready...\n");
            }
            else
            {
                lg.LogMessage(Error, "epoll wait failed\n");
            }
        }
    }
    ~EpollServer()
    {
    }

private:
    std::unique_ptr<NetWork::Socket> _listen_sock;
    std::unique_ptr<Epoll::Epoller> _epoller;
    bool _isrunning;
    int _port;

    struct epoll_event _events[max_events];
};